知识点名称:AsyncTask的使用
编号: K10-3
前驱知识点编号:K10-2,K3-1
作者:
AsyncTask和Handler的功能都是为了不阻塞主线程(UI线程),且UI的更新只能在主线程中完成,但它比Handler在代码上更轻量级一些,也就是更简单易用,由于AsyncTask使用了线程池,所以它比较耗费资源,只有当异步任务数量庞大时,才能充分体现AsyncTask的优势。下面我们先通过实例看AsyncTask是如何实现异步处理的。
AsyncTask是抽象类,因此,我们首先要通过继承它,定义自己的异步类,然后,在实现耗时操作的地方调用自定义的AsyncTask类。
1. AsyncTask类
AsyncTask定义了三种泛型类型,其中:
Params:是启动任务执行的输入参数,比如要实现异步下载,该参数可能传入的是下载的URL值,如果不需要传递参数,可以设置为void.
Progress:后台任务(或称为子线程)执行的百分比
Result:后台执行任务结果的返回值类型。和doInBackground()方法的返回值类型保持一致。
AsyncTask类中的方法:
在此,结合一个异步任务执行的一般过程来分析AsyncTask类中所包含的方法。
1) onPreExecute()方法:执行一个异步任务,需要首先在代码中调用execute(Params... params)方法,来触发异步任务的执行,异步任务执行就会自动回调onPreExecute(),该方法一般用来在执行后台任务前对UI做一些标记。
2) doInBackground(Params... params)方法:在onPreExecute()完成后立即执行,用于执行较为费时的操作,此方法将接收输入参数和返回计算结果。在执行过程中可以调用publishProgress(Progress... values)来更新进度信息。
3) onProgressUpdate(Progress... values)方法:在调用publishProgress(Progress... values)时,此方法被执行,直接将进度信息更新到UI组件上。
4) onPostExecute(Result result) 方法:当后台操作结束时,此方法将会被调用,计算结果将做为参数传递到此方法中,直接将结果显示到UI组件上。
以上四个方法会被自动回调,无需手动调用,否则会出错。另外,还有onCancelled()方法,用来执行用户调用取消时,要做的操作。
2.自定义AsyncTask类
自定义的AsyncTask类要继承AsyncTask<Params,Progress,Result>,并实现其中的某些方法。
下面用AsyncTask类来实现在Handler中进度条更新的例题。
//模拟网络环境
public class NetOperator {
public void operator(){
try {
//休眠1秒
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
class ProgressBarAsyncTask extends AsyncTask<Integer, Integer, String>{
private Button button;
private ProgressBar progressBar;
public ProgressBarAsyncTask(Button button, ProgressBar progressBar) {
super();
this.button=button;
this.progressBar = progressBar;
}
/**
* 这里的Integer参数对应AsyncTask中的第一个参数
* 这里的String返回值对应AsyncTask的第三个参数
* 该方法并不运行在UI线程当中,主要用于异步操作,所有在该方法中不能对UI当中的空间进行设置和修改
* 但是可以调用publishProgress方法触发onProgressUpdate对UI进行操作
*/
protected String doInBackground(Integer... params) {
// TODO Auto-generated method stub
NetOperator netOperator = new NetOperator();
int i = 0;
for (i = 10; i <= 100; i+=10) {
netOperator.operator();
publishProgress(i);
}
return i + params[0].intValue() + "";
}
/**
* 这里的String参数对应AsyncTask中的第三个参数(也就是接收doInBackground的返回值)
* 在doInBackground方法执行结束之后在运行,并且运行在UI线程当中 可以对UI空间进行设置
*/
@Override
protected void onPostExecute(String result) {
System.out.println("异步操作执行结束" + result);
}
//该方法运行在UI线程当中,并且运行在UI线程当中 可以对UI空间进行设置
@Override
protected void onPreExecute() {
System.out.println("开始执行异步线程");
}
/**
* 这里的Intege参数对应AsyncTask中的第二个参数
* 在doInBackground方法当中,,每次调用publishProgress方法都会触发onProgressUpdate执行
* onProgressUpdate是在UI线程中执行,所有可以对UI空间进行操作
*/
@Override
protected void onProgressUpdate(Integer... values) {
int vlaue = values[0];
progressBar.setProgress(vlaue);
}
}
}
下面演示对自定义的AsyncTask类的调用
public class MainActivity extends ActionBarActivity {
private Button button;
private ProgressBar progressBar;
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
button = (Button)findViewById(R.id.button1);
progressBar = (ProgressBar)findViewById(R.id.progressBar1);
button.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
ProgressBarAsyncTask asyncTask = new ProgressBarAsyncTask(button, progressBar);
asyncTask.execute(1000);
}
});
}
自此,我们知道Android系统为了提高程序的实时响应能力,不允许在UI线程中进行耗时的操作,否则会出现ANR异常,因此必须将耗时的任务放到非UI线程中执行。Android提供了很多类来帮助大家完成异步操作,比如:Thread类, AsyncTask类,Handler类等,本章就这些类给出了详细的使用,并介绍了它们之间的区别。